﻿using System;
using System.Diagnostics;
using System.Globalization;
using My.Extensions;
using My.Exceptions;

namespace My.Ioc.Helpers
{
    static class Requires
    {
        public static void True(bool value, string message)
        {
            if (!value)
                throw new PreconditionException(message);
        }

        public static void NotNull(object value, string paramName)
        {
            if (value == null)
                throw new PreconditionException(string.Format(CultureInfo.InvariantCulture,
                    Resources.ObjectCanNotBeNull, paramName));
        }

        public static void NotNullOrEmpty(string value, string paramName)
        {
            if (string.IsNullOrEmpty(value))
                throw new PreconditionException(string.Format(CultureInfo.InvariantCulture,
                    Resources.StringCanNotBeNullOrEmpty, paramName));
        }

        [Conditional("DEBUG")]
        public static void Assert(bool value, string message)
        {
            if (!value)
                throw new AssertionException(message);
        }

        [Conditional("DEBUG")]
        public static void EnsureTrue(bool value, string message)
        {
            if (!value)
                throw new PostconditionException(message);
        }

        [Conditional("DEBUG")]
        public static void EnsureNotNull(object value, string paramName)
        {
            if (value == null)
                throw new PostconditionException(string.Format("The [{0}] must make sure by itself that it is not null!", paramName));
        }

        [Conditional("DEBUG")]
        public static void EnsureNotNullOrEmpty(string value, string paramName)
        {
            if (string.IsNullOrEmpty(value))
                throw new PostconditionException(string.Format("The [{0}] must make sure by itself that it is not null or empty!", paramName));
        }

        internal static void IsAutowirableType(Type type, string paramName)
        {
            if (!type.IsAutowirable())
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                                    Resources.SuppliedTypeIsNotAutowirable, type.ToFullTypeName()), paramName);
        }

        internal static void IsPublicType(Type type, string paramName)
        {
            if (!type.IsPublic())
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                    Resources.SuppliedTypeIsNotPublicType, type.ToFullTypeName()), paramName);
        }

        internal static void IsConcreteType(Type type, string paramName)
        {
            if (!type.IsClass || type.IsAbstract)
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, 
                    Resources.SuppliedTypeIsNotConcreteType, type.ToFullTypeName()), paramName);
        }

        internal static void IsNotOpenGenericType(Type type, string paramName)
        {
            // We check for ContainsGenericParameters to see whether there is a Generic Parameter 
            // to find out if this type can be created.
            if (type.ContainsGenericParameters)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                    Resources.SuppliedTypeIsOpenGeneric,
                    type.ToFullTypeName()), paramName);
            }
        }

        internal static void IsOpenGenericType(Type type, string paramName)
        {
            if (!type.ContainsGenericParameters)
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                                Resources.SuppliedTypeIsNotOpenGeneric, type.ToFullTypeName()), paramName);
        }

        internal static void IsAssignableFrom(Type baseType, Type subType)
        {
            if (baseType != subType && !baseType.IsAssignableFrom(subType))
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                    Resources.SuppliedTypeIsNotAssignableFromType,
                    baseType.ToFullTypeName(),
                    subType.ToFullTypeName()));
            }
        }

        internal static void IsAssignableFromGeneric(Type openGenericBaseType, Type openGenericSubType)
        {
            if (openGenericBaseType.IsAssignableFromGeneric(openGenericSubType))
                return;
            
            throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                Resources.SuppliedTypeIsNotAssignableFromOpenGenericType,
                openGenericSubType.ToFullTypeName(),
                openGenericBaseType.ToFullTypeName()));
        }

        internal static void HasOneGenericArgument(Type type, string paramName)
        {
            if (type.GetGenericArguments().Length != 1)
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                                                Resources.SuppliedTypeSupposedToHaveOneGenericArgsOnly, type.ToFullTypeName()), paramName);
        }

        //internal static void HasNoArgumentConstructor(Type type, string paramName)
        //{
        //    IsConcreteType(type, paramName);

        //    if (type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) == null)
        //        throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, 
        //            Resources.SuppliedTypeDoesNotHaveNonArgsConstructor, type.ToFullTypeName()), paramName);
        //}
    }
}
